﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Collections.Generic;
namespace DraggableWindow
{
	[TemplatePart(Name = PopupWindow.TitleBarElement, Type = typeof(FrameworkElement))]
	[TemplatePart(Name = PopupWindow.StatusBarElement, Type = typeof(FrameworkElement))]
	[TemplatePart(Name = PopupWindow.WindowBorderElement, Type = typeof(Border))]
	[TemplatePart(Name = PopupWindow.ButtonsElement, Type = typeof(Panel))]
	[TemplatePart(Name = PopupWindow.ContentContainerElement, Type = typeof(Border))]
	[TemplatePart(Name = PopupWindow.CloseButtonElement, Type = typeof(Button))]
	[TemplatePart(Name = PopupWindow.ResizeElement, Type = typeof(FrameworkElement))]
	[TemplatePart(Name = PopupWindow.TitleTextElement, Type = typeof(ContentPresenter ))]
    [TemplatePart(Name = PopupWindow.StatusBarPresenterElement, Type = typeof(ContentPresenter))]
	

    [TemplatePart(Name = PopupWindow.StatusRowElement , Type = typeof(RowDefinition ))]
    [TemplateVisualState(Name = PopupWindow.WindowStateOpen, GroupName = PopupWindow.WindowStateGroup)]
    [TemplateVisualState(Name = PopupWindow.WindowStateClosed , GroupName = PopupWindow.WindowStateGroup)]
	public class PopupWindow : DragDropControl
	{
		private const string TitleBarElement = "TitleBar";
        private const string TitleTextElement = "TitleText";
        private const string StatusBarPresenterElement = "StatusBarPresenter";
		private const string StatusBarElement = "StatusBar";
		private const string ButtonsElement = "Buttons";
		private const string ContentContainerElement = "ContentContainer";
		private const string WindowBorderElement = "WindowBorder";
		private const string CloseButtonElement = "CloseButton";
		private const string ResizeElement = "ResizeImage";
		
        private const string StatusRowElement = "StatusRow";

        protected const string WindowStateGroup = "WindowStates";
        protected const string WindowStateOpen = "Open";
        protected const string WindowStateClosed = "Closed";

        protected ContentPresenter StatusBarPresenter;
        protected ContentPresenter TitleText;
		protected Button CloseButton;
		protected Border ContentContainer;
		protected Border WindowBorder;
		protected FrameworkElement ResizeImage;
		protected FrameworkElement StatusBar;
		
        protected RowDefinition StatusRow;

        protected PopupWindowState WindowState;
        protected bool showWindow;
        /// <summary>
        /// Raised when the the popup window has been closed
        /// </summary>
        public event EventHandler PopupClosed;

        
        #region properties
    


        #region StatusVisibility

        /// <summary>
        /// Identifies the <see cref="StatusVisibility"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty StatusVisibilityProperty =
            DependencyProperty.Register("StatusVisibility", typeof(Visibility), typeof(PopupWindow),
              new PropertyMetadata(
                new PropertyChangedCallback(OnStatusVisibilityChanged)
              ));

        /// <summary>
        /// Gets or sets the visiblity of the status bar
        /// </summary>
        public Visibility StatusVisibility
        {
            get { return (Visibility)GetValue(StatusVisibilityProperty); }
            set { SetValue(StatusVisibilityProperty, value); }
        }

        /// <summary>
        /// Handles changes to the StatusVisibility property.
        /// </summary>
        private static void OnStatusVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ( (PopupWindow)d ).OnStatusVisibilityChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the StatusVisibility property.
        /// </summary>
        protected virtual void OnStatusVisibilityChanged(DependencyPropertyChangedEventArgs e)
        {
            ToggleStatusRow();
        }

        /// <summary>
        /// Toggle the visiblity of the status row
        /// </summary>
        private void ToggleStatusRow()
        {
            if ( StatusRow != null )
            {
                if ( StatusVisibility == Visibility.Collapsed )
                {
                    StatusRow.MaxHeight = 0;
                }
                else
                {
                    StatusRow.MaxHeight = Double.PositiveInfinity;
                }
            }
        }

        #endregion


        #region CloseButtonStyle

        /// <summary>
        /// Identifies the <see cref="CloseButtonStyle"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty CloseButtonStyleProperty =
            DependencyProperty.Register("CloseButtonStyle", typeof(Style), typeof(PopupWindow),
              new PropertyMetadata(
                new PropertyChangedCallback(OnCloseButtonStyleChanged)
              ));

        /// <summary>
        /// Gets or sets the style for the close button
        /// </summary>
        public Style CloseButtonStyle
        {
            get { return (Style)GetValue(CloseButtonStyleProperty); }
            set { SetValue(CloseButtonStyleProperty, value); }
        }

        /// <summary>
        /// Handles changes to the CloseButtonStyle property.
        /// </summary>
        private static void OnCloseButtonStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ( (PopupWindow)d ).OnCloseButtonStyleChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the CloseButtonStyle property.
        /// </summary>
        protected virtual void OnCloseButtonStyleChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        #endregion




		#region Title

		/// <summary>
		/// Identifies the Title dependency property.
		/// </summary>
		public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
            "Title", typeof(Object), typeof(PopupWindow), null);

		/// <summary>
		/// Gets or sets the Title possible Value of the string object.
		/// </summary>
        public Object Title
		{
            get { return (Object)GetValue(TitleProperty); }
			set { SetValue(TitleProperty, value); }
		}

		#endregion Title

        #region TitleTemplate

        /// <summary>
        /// Identifies the <see cref="TitleTemplate"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty TitleTemplateProperty =
            DependencyProperty.Register("TitleTemplate", typeof(DataTemplate), typeof(PopupWindow),
              new PropertyMetadata(
                new PropertyChangedCallback(OnTitleTemplateChanged)
              ));

        /// <summary>
        /// Template used for the Title object
        /// </summary>
        public DataTemplate TitleTemplate
        {
            get { return (DataTemplate)GetValue(TitleTemplateProperty); }
            set { SetValue(TitleTemplateProperty, value); }
        }

        /// <summary>
        /// Handles changes to the TitleTemplate property.
        /// </summary>
        private static void OnTitleTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ( (PopupWindow)d ).OnTitleTemplateChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the TitleTemplate property.
        /// </summary>
        protected virtual void OnTitleTemplateChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        #endregion

		#region TitleBackground

		/// <summary>
		/// Identifies the TitleBackground dependency property.
		/// </summary>
		public static readonly DependencyProperty TitleBackgroundProperty = DependencyProperty.Register(
            "TitleBackground", typeof(Brush), typeof(PopupWindow), null);

		/// <summary>
        /// Gets or sets the background of the Title area
		/// </summary>
        public Brush TitleBackground
		{
			get { return (Brush)GetValue(TitleBackgroundProperty); }
			set { SetValue(TitleBackgroundProperty, value); }
		}
		#endregion TitleBackground

        //#region TitleForeground

        ///// <summary>
        ///// Identifies the <see cref="TitleForeground"/> dependency property.
        ///// </summary>
        //public static readonly DependencyProperty TitleForegroundProperty =
        //    DependencyProperty.Register("TitleForeground", typeof(Brush), typeof(PopupWindow),
        //      new PropertyMetadata(
        //        new PropertyChangedCallback(OnTitleForegroundChanged)
        //      ));

        ///// <summary>
        ///// Gets or sets the TitleForeground property.  This dependency property 
        ///// indicates the brushed used for the foreground of the title.
        ///// </summary>
        //[Category("Brushes"),Description("Gets or sets the foreground brushed used in the title")]
        //public Brush TitleForeground
        //{
        //    get { return (Brush)GetValue(TitleForegroundProperty); }
        //    set { SetValue(TitleForegroundProperty, value); }
        //}

        ///// <summary>
        ///// Handles changes to the TitleForeground property.
        ///// </summary>
        //private static void OnTitleForegroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        //{
        //    ( (PopupWindow)d ).OnTitleForegroundChanged(e);
        //}

        ///// <summary>
        ///// Provides derived classes an opportunity to handle changes to the TitleForeground property.
        ///// </summary>
        //protected virtual void OnTitleForegroundChanged(DependencyPropertyChangedEventArgs e)
        //{
        //}

        //#endregion


        #region Status

        /// <summary>
        /// Identifies the <see cref="Status"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty StatusProperty =
            DependencyProperty.Register("Status", typeof(object), typeof(PopupWindow),
              new PropertyMetadata(
                new PropertyChangedCallback(OnStatusChanged)
              ));

        /// <summary>
        /// Gets or sets an object that labels the status bar
        /// </summary>
        public object Status
        {
            get { return (object)GetValue(StatusProperty); }
            set { SetValue(StatusProperty, value); }
        }

        /// <summary>
        /// Handles changes to the Status property.
        /// </summary>
        private static void OnStatusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ( (PopupWindow)d ).OnStatusChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the Status property.
        /// </summary>
        protected virtual void OnStatusChanged(DependencyPropertyChangedEventArgs e)
        {
            

        }

        #endregion

        #region StatusTemplate

        /// <summary>
        /// Identifies the <see cref="StatusTemplate"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty StatusTemplateProperty =
            DependencyProperty.Register("StatusTemplate", typeof(DataTemplate), typeof(PopupWindow),
              new PropertyMetadata(
                new PropertyChangedCallback(OnStatusTemplateChanged)
              ));

        /// <summary>
        /// Template used for the Status object
        /// </summary>
        public DataTemplate StatusTemplate
        {
            get { return (DataTemplate)GetValue(StatusTemplateProperty); }
            set { SetValue(StatusTemplateProperty, value); }
        }

        /// <summary>
        /// Handles changes to the StatusTemplate property.
        /// </summary>
        private static void OnStatusTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ( (PopupWindow)d ).OnStatusTemplateChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the StatusTemplate property.
        /// </summary>
        protected virtual void OnStatusTemplateChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        #endregion



        #region StatusBarBackground

        /// <summary>
        /// Identifies the <see cref="StatusBarBackground"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty StatusBarBackgroundProperty =
            DependencyProperty.Register("StatusBarBackground", typeof(Brush), typeof(PopupWindow),
              new PropertyMetadata(
                new PropertyChangedCallback(OnStatusBarBackgroundChanged)
              ));

        /// <summary>
        /// Gets or sets the brush used for the background of the Status Bar
        /// </summary>
        public Brush StatusBarBackground
        {
            get { return (Brush)GetValue(StatusBarBackgroundProperty); }
            set { SetValue(StatusBarBackgroundProperty, value); }
        }

        /// <summary>
        /// Handles changes to the StatusBarBackground property.
        /// </summary>
        private static void OnStatusBarBackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ( (PopupWindow)d ).OnStatusBarBackgroundChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the StatusBarBackground property.
        /// </summary>
        protected virtual void OnStatusBarBackgroundChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        #endregion

     



        #endregion

        #region Constructor
        public PopupWindow(bool isOpen)
            : base()
        {
            this.DefaultStyleKey = typeof(PopupWindow);
            this.CanResize = true;
            this.showWindow = isOpen;
            this.Loaded += new RoutedEventHandler(PopupWindow_Loaded);
              
        }

        void PopupWindow_Loaded(object sender, RoutedEventArgs e)
        {

                
        }

       

        public PopupWindow() : this(true)
		{
                    
		}            
		#endregion



        #region Public Methods

        public void Close()
		{
            this.WindowState = PopupWindowState.Closed;
		}


        public void Show()
        {
            this.Dispatcher.BeginInvoke(() =>
            {
                ShowWindow(this.Parent);
            });
        }
        
        #endregion

        protected void ShowWindow(DependencyObject owner, bool useTransitions)
        {
            VisualStateManager.GoToState(this, PopupWindow.WindowStateOpen, useTransitions);
            this.Visibility = Visibility.Visible;
            OnShowWindow(owner);
        }
        protected void ShowWindow(DependencyObject owner)
        {
            ShowWindow(owner, true);
           
        }

        protected virtual void OnShowWindow(DependencyObject owner)
        {

        }
        protected void HideWindow()
        {
            HideWindow(true);

        }
        protected void HideWindow(bool useTransitions)
        {
            VisualStateManager.GoToState(this, PopupWindow.WindowStateClosed, useTransitions);
            this.Visibility = Visibility.Collapsed;
            OnHideWindow();
        }
        protected virtual void OnHideWindow()
        {

        }

        private void OnPopupClosing()
        {
            VisualStateManager.GoToState(this, PopupWindow.WindowStateClosed, true);
            HideWindow();

            OnClose();
            
            EventHandler handler = PopupClosed;

            if ( handler != null )
            {
                handler(this, new EventArgs());
            }
                
        }

        protected virtual void OnClose()
        {


        }

		#region Overrides
		public override void OnApplyTemplate()
		{
			base.OnApplyTemplate();

			WindowBorder = GetTemplateChild(WindowBorderElement) as Border;

			CloseButton = this.GetTemplateChild(CloseButtonElement) as Button;
			if (CloseButton != null)
				CloseButton.Click +=new RoutedEventHandler(CloseButton_Click);

			ContentContainer = this.GetTemplateChild(ContentContainerElement) as Border;
			if (ContentContainer != null)
				ContentContainer.MouseLeftButtonDown += new MouseButtonEventHandler(ContentContainer_MouseLeftButtonDown);
			ResizeImage = GetTemplateChild(ResizeElement) as FrameworkElement;
			if (ResizeImage != null && !this.CanResize)
				ResizeImage.Visibility = Visibility.Collapsed;
			StatusBar = GetTemplateChild(StatusBarElement) as FrameworkElement;

            StatusRow = GetTemplateChild(StatusRowElement) as RowDefinition;

            StatusBarPresenter = GetTemplateChild(StatusBarPresenterElement) as ContentPresenter;
            TitleText = GetTemplateChild(TitleTextElement ) as ContentPresenter;

            if ( DesignerProperties.GetIsInDesignMode(this) || showWindow )
            {
                ShowWindow(this.Parent, false);

            }
            else
            {
                HideWindow(false);
            }
		}

       
       
		void  CloseButton_Click(object sender, RoutedEventArgs e)
		{
            OnPopupClosing();
		}

		void ContentContainer_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
		{
			e.Handled = true;
		}

        //protected override Size ArrangeOverride(Size finalSize)
        //{
            
        //    Size resultSize = base.ArrangeOverride(finalSize);;
        //    List<UIElement> eles = new List<UIElement>(){
        //        this.Container as UIElement,
        //        this.Content as UIElement ,
        //        this.TitleText as UIElement ,
        //        this.StatusBarPresenter as UIElement
        //    };

        //    foreach ( UIElement ele in eles )
        //    {
        //        if ( ele != null )
        //        {
                    
        //            ele.Arrange(new Rect(new Point(0, 0), ele.DesiredSize));
        //        }
        //    }


        //    return resultSize;
        //}
		
        //protected override Size MeasureOverride(Size availableSize)
        //{

        //    Size resultSize = base.MeasureOverride(availableSize);
        //    List<UIElement> eles = new List<UIElement>(){
        //        this.Container as UIElement,
        //        this.Content as UIElement,
        //        this.TitleText as UIElement,
        //        this.StatusBarPresenter as UIElement 
        //    };

        //    foreach ( UIElement ele in eles )
        //    {
        //        if ( ele != null )
        //        {
        //            ele.Measure(availableSize);
        //            Size thisSize = ele.GetMaxSize(resultSize, availableSize);
                    
        //            // basically, we keep adding to our height (status, title, content)
        //            // and use the biggest width
        //            resultSize.Height += thisSize.Height;
        //            resultSize.Width = Math.Max(thisSize.Width, resultSize.Width );

        //        }
        //    }
        //    resultSize.Width = double.IsPositiveInfinity(availableSize.Width) ?
        //        resultSize.Width : availableSize.Width;

        //    resultSize.Height = double.IsPositiveInfinity(availableSize.Height) ?
        //        resultSize.Height : availableSize.Height;
        //    return resultSize;
            
        //}
        
        #endregion		
	}
}
